
#include <QMap>
#include <QRegExp>

#include "timestampparser.h"
#include "karehaparser.h"
#include "text.h"

namespace Wishmaster
{
	class KarehaParserImpl
	{
	public:
		KarehaParserImpl(const QString& boardname) : m_boardname(boardname) {}
		int parseOpPost(PostInfo& info, const QByteArray& input);

		QString m_boardname;
		TimestampParser m_timestampParser;
	};

	QString Wishmaster::KarehaParser::id()
	{
		return "kareha";
	}

	KarehaParser::KarehaParser(const QString& boardname) : BoardParser()
	{
		m_impl = new KarehaParserImpl(boardname);
	}

	KarehaParser::~KarehaParser()
	{
		delete m_impl;
	}

	int KarehaParserImpl::parseOpPost(PostInfo& info, const QByteArray& input)
	{
		QString thread = QString::fromUtf8(input);
		QString regexp = QString::fromUtf8("<h2>(.*)<small>.*</small></h2>.*<span class=\"postername\">(.*)</span><span class=\"postertrip\">.*</span>([^<]*).*(?:<a href=\"([^\"]*)\"> <img src=\"([^\"]*)\".*class=\"thumb\" /></a>)?\\s+<div class=\"replytext\">(.*)</div> </div>");
		QRegExp rx(regexp, Qt::CaseSensitive, QRegExp::RegExp);
		rx.setMinimal(true);

		int pos = 0;
		pos = rx.indexIn(thread, pos);
		if(pos == -1)
			return 0;

		info.topic = htmlToPlainText(rx.cap(1));
		info.name = htmlToPlainText(rx.cap(2));
		info.text = rx.cap(6);
		info.timestamp = m_timestampParser.parse(rx.cap(3)).toTime_t();

		if(!rx.cap(4).isEmpty())
		{
			AttachmentInfo picture;
			picture.thumbUrl = QUrl(rx.cap(5));
			picture.url = QUrl(rx.cap(4));
			info.attachments.append(picture);
		}

		return pos + rx.matchedLength();
	}

	PostId KarehaParser::getPostID(const QString& link, const ThreadId& threadId)
	{
		if(link.trimmed().isEmpty())
			return PostId();
		QString regexp = QString("/%1/(\\d+)").arg(threadId.threadNumericId());
		QRegExp rx(regexp);
		if(rx.indexIn(link) != -1)
		{
			return PostId(threadId.chanName(), threadId.boardId(), threadId.threadNumericId(), rx.cap(1).toULong());
		}
		return PostId();
	}

	QList<PostId> KarehaParser::findLinks(const ThreadId& threadId, const QString& posttext)
	{
		QList<PostId> list;
		QRegExp rx("&gt;&gt;(\\d+)</a>");
		int pos = 0;
		while((pos = rx.indexIn(posttext, pos)) != -1)
		{
			unsigned int postId = rx.cap(1).toUInt();
			if(postId != 0)
			{
				list.append(PostId(threadId.chanName(), threadId.boardId(), threadId.threadNumericId(), postId));
			}
			pos += rx.matchedLength();
		}
		return list;
	}

	QList<PostInfo> KarehaParser::getPosts(const ThreadId& threadId, const QByteArray& input)
	{
		QList<PostInfo> list;
		QMap<PostId , int> postPositions;
		list.clear(); // just in case
		PostInfo oppost;
		int pos = m_impl->parseOpPost(oppost, input);
		if(pos == 0)
		{
			return list;
		}
		oppost.post_id = PostId(threadId.chanName(), threadId.boardId(), threadId.threadNumericId(), 1);
		list.append(oppost);

		postPositions.insert(oppost.post_id, 0);

		QString thread = QString::fromUtf8(input);
		QString regexp = QString::fromUtf8(">(\\d+)</a>.*<span class=\"postername\">(.*)</span><span class=\"postertrip\">.*</span>([^<]*).*(?:<a href=\"([^\"]*)\"> <img src=\"([^\"]*)\".*class=\"thumb\" /></a>)?\\s+<div class=\"replytext\">(.*)</div> </div>");
		QRegExp rx(regexp, Qt::CaseSensitive, QRegExp::RegExp);
		rx.setMinimal(true);

		int post_position = 1;
		while((pos = rx.indexIn(thread, pos)))
		{
			if(pos == -1)
				break;
			pos += rx.matchedLength();
			PostInfo post;
			post.topic = "";
			post.text = rx.cap(6);
			post.name = rx.cap(2);
			post.timestamp = m_impl->m_timestampParser.parse(rx.cap(3)).toTime_t();
			toPlainText(post.name);

			if(!rx.cap(4).isEmpty())
			{
				AttachmentInfo picture;
				picture.thumbUrl = QUrl(rx.cap(5));
				picture.url = QUrl(rx.cap(4));
				post.attachments.append(picture);
			}

			post.post_id = PostId(threadId.chanName(), threadId.boardId(), threadId.threadNumericId(), rx.cap(1).toUInt());
			QList<PostId> links = findLinks(threadId, post.text);
			foreach(PostId link, links)
			{
				list[postPositions.value(link)].replies.insert(post.post_id);
			}

			list.append(post);
			postPositions.insert(post.post_id, post_position);
			post_position++;
		}
		return list;
	}

	QList<ThreadInfo> KarehaParser::getThreadList(const QString& chanName, const QString& boardId, const QByteArray& input)
	{
		QList<ThreadInfo> list;
		QString str(input);
		QString thread_regexp = "<span class=\"threadlink\">\\s*<a href=\"%BOARD%kareha.pl/(\\d+)/[^\"]*\" rel=\"nofollow\">\\d*:(.*)\\((\\d*)\\)</a>\\s+</span>";
		thread_regexp.replace(QString("%BOARD%"), boardId);
		QRegExp rx(thread_regexp, Qt::CaseSensitive, QRegExp::RegExp2);
		unsigned int order = QDateTime::currentDateTime().toTime_t();
		rx.setMinimal(true);
		int pos = 0;
		while((pos = rx.indexIn(str, pos)) != -1)
		{
			ThreadInfo info;
			info.thread_id = ThreadId(chanName, boardId, rx.cap(1).toULong());
			info.topic = htmlToPlainText(QString::fromUtf8(rx.cap(2).toAscii()));
			info.topic = info.topic.trimmed();
			if(info.topic.isEmpty())
			{
				info.topic = QString("#") + info.thread_id.threadStringId();
			}
			int posts = rx.cap(3).toInt();
			if(posts == 0)
				info.posts = 1;
			else
				info.posts = posts;
			info.timestamp = order--;
			pos += rx.matchedLength();
			list.append(info);
		}
		return list;
	}

	BoardParser* KarehaParser::clone(const QString& boardname)
	{
		return new KarehaParser(boardname);
	}

	void KarehaParser::setTimestampFormat(const QString& format)
	{
		m_impl->m_timestampParser.setPattern(format);
	}
}


Q_EXPORT_PLUGIN2(karehaparser, Wishmaster::KarehaParser)


